module ysyx_22040213_cache(
	input clk,
	input rst,
	
	//cache cpu interface
	input i_cache_req,
	input i_cache_wr,
	input [63:0] i_cache_addr,
	input [63:0] i_cache_wdata,
	input [7:0] i_cache_wstrb,

	output o_cache_addr_ok,
	output o_cache_data_ok,
	output [63:0] o_cache_rdata,


	//cache axi interface
	output o_cache_rd_req,
	output [2:0] o_cache_rd_type,
	output [63:0] o_cache_rd_addr,
	input i_cache_rd_rdy,

	input i_cache_ret_valid,
	input i_cache_ret_last,
	input [63:0] i_cache_ret_data,
	
	output o_cache_wr_req,
	output [2:0] o_cache_wr_type,
	output [63:0] o_cache_wr_addr,
        output [7:0] o_cache_wr_wstrb,
	output [63:0] o_cache_wr_data,
	input i_cache_wr_rdy,	
	//difftest//
	output devices_access
);
/* verilator lint_off UNUSED */
`define IDLE        3'b000
`define LOOKUP      3'b001
`define MISS        3'b010
`define REPLACE     3'b011
`define REFILL      3'b100
`define WRITE_IDLE  1'b0
`define WRITE_WRITE 1'b1
`define SERIAL      64'ha00003f8
`define RTC         64'ha0000048
`define FB_ADDR     64'ha1000000
`define SYN_ADDR    64'ha0000104

//wire need = dataram_addr4 == 6'b000000 & !dataram_wen4 & !dataram_cen4; 
//--TAG_V D reg interface-----//
reg [52:0] cache_tagv; //52:1 tag ; 0: v
reg cache_D;

wire [51:0] cache_tag;
wire cache_v;

assign cache_tag = cache_tagv[52:1];
assign cache_v = cache_tagv[0];

//------------dataram------//
wire [127:0] dataram_rdata;
wire [63:0] dataram_cacheline_sel;
wire [31:0] dataram_rdata_4word;
wire [63:0] dataram_to_loadword;

assign dataram_rdata =     (req_index[8:7] == 2'b00)? dataram_rdata1 : 
			   (req_index[8:7] == 2'b01)? dataram_rdata2 : 
			   (req_index[8:7] == 2'b10)? dataram_rdata3 : 
			   (req_index[8:7] == 2'b11)? dataram_rdata4 : 128'b0;

wire sel_high_cacheline = req_index[0];
wire sel_high_word      = req_offset[2];

assign dataram_cacheline_sel = !req_index[0] ? dataram_rdata[63:0] : dataram_rdata[127:64];
assign dataram_rdata_4word = req_offset[2] ? dataram_cacheline_sel[63:32] : dataram_cacheline_sel[31:0];
MuxKey #(8, 3, 64) i6 (dataram_to_loadword, req_offset, {
	3'b000,  dataram_cacheline_sel,
	3'b001,  {{8'b0},dataram_cacheline_sel[63:8]},
	3'b010,  {{16'b0},dataram_cacheline_sel[63:16]},
	3'b011,  {{24'b0},dataram_cacheline_sel[63:24]},
	3'b100,  {{32'b0},dataram_cacheline_sel[63:32]},
	3'b101,  {{40'b0},dataram_cacheline_sel[63:40]},
	3'b110,  {{48'b0},dataram_cacheline_sel[63:48]},
	3'b111,  {{56'b0},dataram_cacheline_sel[63:56]}	
});


//----contrl-signal----//
wire hit_write_harzard;
wire hit_write;
wire hit;
reg [2:0] cache_state;
wire [8:0]  index;
wire dataram_wen;
reg cache_wr_req;
wire [63:0] cache_wdata;
wire [63:0] cache_wstrb;

MuxKey #(4, 8, 64) i5 (cache_wstrb, i_cache_wstrb, {
	8'h01, 64'hff,	
	8'h03, 64'hffff,
	8'h0f, 64'hffffffff,
	8'hff, 64'hffffffffffffffff
});

assign cache_wdata = i_cache_wdata & cache_wstrb;
assign index = i_cache_addr[11:3];
assign dataram_wen = ((cache_state == `REFILL) && (i_cache_ret_valid && i_cache_ret_last)) || write_buffer_req;

assign hit_write = (cache_state == `LOOKUP) && (req_wr == 1'b1) && hit;
//assign hit_write_harzard =  ((cache_state == `LOOKUP) && (req_wr == 1'b1) && (i_cache_addr == req_addr)) 
//			 || (write_buffer_state == 1'b1 && i_cache_addr == write_buffer_addr);
//assign hit_write_harzard =  ((cache_state == `LOOKUP) && (req_wr == 1'b1) && (hit) && (i_cache_addr == req_addr) && i_cache_req && ~i_cache_wr) 
//			 || (i_cache_req && ~i_cache_wr && write_buffer_state == 1'b1 && i_cache_addr == write_buffer_addr );
assign hit_write_harzard =  ((cache_state == `LOOKUP) && (req_wr == 1'b1) && (hit) && (index[8:7] == req_index[8:7]) && i_cache_req && ~i_cache_wr) 
			 || (i_cache_req && ~i_cache_wr && write_buffer_state == 1'b1 && index[8:7] == write_buffer_addr[11:10] );


assign o_cache_addr_ok = (cache_state == `IDLE && ~hit_write_harzard) 
		    || (((cache_state == `LOOKUP) && i_cache_req && hit) && ((i_cache_wr == 1'b1)||(i_cache_wr == 1'b0 && ~hit_write_harzard)));
assign o_cache_data_ok = (cache_state == `LOOKUP && ( hit || req_wr == 1'b1)) || (cache_state == `REFILL && i_cache_ret_valid);

assign o_cache_rd_req = (cache_state == `REPLACE);
assign o_cache_rd_addr = o_cache_rd_req ? {{req_tag},{req_index},{3'b0}} : 64'b0;//cache line replace
assign o_cache_rd_type = 3'b0;

assign o_cache_wr_req   = missbuffer_cache_D || uncache ? cache_wr_req : 1'b0; //D == 1 write_back
assign o_cache_wr_addr  = !uncache ? {{missbuffer_cache_tag},{missbuffer_index},{3'b0}} : req_addr;
assign o_cache_wr_wstrb = !uncache ? 8'hff : req_wstrb;
assign o_cache_wr_type  = 3'b100; 
assign o_cache_wr_data  = missbuffer_rdata & {64{!uncache}}  | {64{uncache}} & req_wdata;

assign devices_access = ((i_cache_addr == `SERIAL) || (i_cache_addr == `RTC) || (i_cache_addr == `RTC+4) || (i_cache_addr >= 64'ha0000000)) && i_cache_req;
//wire req_device_access;


//--------------Request buffer-------------//
reg req_req;
reg req_wr;
reg [63:0] req_addr;
reg [63:0] req_wdata;
reg [7:0] req_wstrb;
reg req_type;

Reg #(1,  1'b0) i0 (clk, rst, i_cache_req, req_req, (cache_state == `IDLE) & (i_cache_req && ~hit_write_harzard )|| (cache_state == `LOOKUP) & (hit && i_cache_req && ~hit_write_harzard));
Reg #(1,  1'b0) i1 (clk, rst, i_cache_wr,  req_wr,  (cache_state == `IDLE) & (i_cache_req && ~hit_write_harzard )|| (cache_state == `LOOKUP) & (hit && i_cache_req && ~hit_write_harzard));
Reg #(64, 64'b0) i2 (clk, rst, i_cache_addr, req_addr, (cache_state == `IDLE) & (i_cache_req && ~hit_write_harzard )|| (cache_state == `LOOKUP) & (hit && i_cache_req && ~hit_write_harzard));
Reg #(64, 64'b0) i3 (clk, rst, cache_wdata, req_wdata, (cache_state == `IDLE) & (i_cache_req && ~hit_write_harzard )|| (cache_state == `LOOKUP) & (hit && i_cache_req && ~hit_write_harzard));
Reg #(8,  8'b0) i4 (clk, rst, i_cache_wstrb, req_wstrb, (cache_state == `IDLE) & (i_cache_req && ~hit_write_harzard )|| (cache_state == `LOOKUP) & (hit && i_cache_req && ~hit_write_harzard));
//Reg #(1,  1'b0) i6 (clk, rst, i_cache_type, req_type,(i_cache_req && ~hit_write_harzard)||(hit && i_cache_req && ~hit_write_harzard));

wire [51:0] req_tag;
wire [2:0] req_offset;
wire [8:0] req_index;
wire uncache;

assign req_index  = req_addr[11:3];
assign req_tag    = req_addr[63:12];
assign req_offset = req_addr[2:0];
//assign req_device_access = req_addr >= 64'h00000000a0000000;
assign uncache = (req_addr == `SERIAL) || (req_addr == `RTC) || (req_addr == `RTC+4) || (req_addr == `SYN_ADDR) || (req_addr >= `FB_ADDR);


//-------Tag compare-------------//
//ignore uncache
assign hit = (cache_state == `LOOKUP) && cache_v && (req_tag == cache_tag) && (req_addr != `SERIAL) && (req_addr != `RTC) && (req_addr != `RTC+4);

//--------Data select------------//
wire [63:0] axi_ret_data;
assign axi_ret_data = req_wr ? i_cache_ret_data & req_wdata                                          
	                     : o_cache_ret_data; 
wire [63:0] o_cache_ret_data;

MuxKey #(8, 3, 64) i15 (o_cache_ret_data, req_offset, {
	3'b000,  i_cache_ret_data,
	3'b001,  {{8'b0},i_cache_ret_data[63:8]},
	3'b010,  {{16'b0},i_cache_ret_data[63:16]},
	3'b011,  {{24'b0},i_cache_ret_data[63:24]},
	3'b100,  {{32'b0},i_cache_ret_data[63:32]},
	3'b101,  {{40'b0},i_cache_ret_data[63:40]},
	3'b110,  {{48'b0},i_cache_ret_data[63:48]},
	3'b111,  {{56'b0},i_cache_ret_data[63:56]}	

});

wire [63:0] load_word = {64{hit}} & {dataram_to_loadword} | {64{~hit && i_cache_ret_valid && i_cache_ret_last}} & {axi_ret_data};

/*
wire [63:0] load_word_test = {64{hit}} & {{32'b0},{dataram_rdata_4word}} | {64{~hit && i_cache_ret_valid && i_cache_ret_last}} & {{32{1'b0}},axi_ret_data};
wire diff_load = (load_word[31:0] != load_word_test[31:0]) && o_cache_data_ok;
*/

wire [63:0] replace_data = load_word; //no other ways
assign o_cache_rdata = load_word;

wire [127:0] axidata_to_dataram = req_wr ? {{i_cache_ret_data},{i_cache_ret_data}} & ~write_buffer_bwen | write_data & write_buffer_bwen
			                 : {{i_cache_ret_data},{i_cache_ret_data}};
//Miss buffer//
wire [63:0] missbuffer_rdata = dataram_cacheline_sel;
wire missbuffer_cache_D = cache_D;
wire [51:0] missbuffer_cache_tag = cache_tag;

wire [8:0] missbuffer_index;
//Reg #(64,  64'b0) i10 (clk, rst, dataram_cacheline_sel, missbuffer_rdata, (cache_state == `MISS) & i_cache_wr_rdy);
//Reg #(52,  52'b0) i11 (clk, rst, cache_tag, missbuffer_cache_tag , (cache_state == `MISS) & i_cache_wr_rdy);
//Reg #(1,    1'b0) i12 (clk, rst, cache_D, missbuffer_cache_D , (cache_state == `MISS) & i_cache_wr_rdy);
Reg #(9,    9'b0) i13 (clk, rst, req_index, missbuffer_index , (cache_state == `MISS) & i_cache_wr_rdy);


//Write buffer//
reg write_buffer_state;
reg write_buffer_req;
reg [63:0] write_buffer_addr;
reg [7:0]  write_buffer_wstrb;
reg [127:0] write_buffer_wdata;
reg [127:0] o_write_buffer_bwen;
wire [8:0] write_buffer_index;
assign write_buffer_index = write_buffer_addr[11:3];

// cache finite state machine//
always @(posedge clk)begin
  if(rst)begin
    cache_state <= `IDLE;
    cache_wr_req <= 1'b0;
  end else begin
    if(i_cache_wr_rdy)begin
      cache_wr_req <= 1'b0;
    end
    case(cache_state)
      `IDLE: begin
	if(i_cache_req && ~hit_write_harzard)begin
	  cache_state <= `LOOKUP;
	end else begin
	end		
      end
      `LOOKUP: begin
        if((hit && ~i_cache_req) || (hit & hit_write_harzard && i_cache_req))begin
	  cache_state <= `IDLE;
	end else if(hit && i_cache_req && ~hit_write_harzard)begin
	  cache_state <= `LOOKUP;
  	end else if(~hit) begin
  	  cache_state <= `MISS;
  	end else begin
        end
      end
      `MISS: begin
      	if(i_cache_wr_rdy)begin
	  cache_state <= `REPLACE;
	  cache_wr_req <= 1'b1;
        end
      end
      `REPLACE: begin
        if(i_cache_rd_rdy)begin
	  cache_state <= `REFILL;
	end else begin
	end
      end
      `REFILL: begin
        if(i_cache_ret_valid && i_cache_ret_last)begin
	  cache_state <= `IDLE;
	end else begin
	end
      end
      default: begin
        cache_state <= `IDLE;
      end
    endcase
  end
end
//write buffer infinite machine// //syn with req buffer//
wire [63:0] write_buffer_bwen_half;// = (req_wstrb == 8'hff) ? 64'hffffffffffffffff : sel_high_word ? 64'hffffffff00000000 : 64'h00000000ffffffff;

MuxKey #(8, 3, 64) i9 (write_buffer_bwen_half, req_offset, {
	3'b000,  o_req_wstrb,
	3'b001,  {{o_req_wstrb[55:0]},{8'b0}},
	3'b010,  {{o_req_wstrb[47:0]},{16'b0}},
	3'b011,  {{o_req_wstrb[39:0]},{24'b0}},
	3'b100,  {{o_req_wstrb[31:0]},{32'b0}},
	3'b101,  {{o_req_wstrb[23:0]},{40'b0}},
	3'b110,  {{o_req_wstrb[15:0]},{48'b0}},
	3'b111,  {{o_req_wstrb[7:0]}, {56'b0}}
});

wire [127:0] write_buffer_bwen = sel_high_cacheline ? {{write_buffer_bwen_half},{64'h0}} : {{64'h0},{write_buffer_bwen_half}};
//wire [63:0] writedata_to_dataram = (req_wstrb == 8'hff) ? req_wdata :  {{req_wdata[31:0]},{req_wdata[31:0]}};
wire [63:0] o_req_wstrb;
MuxKey #(4, 8, 64) i7 (o_req_wstrb, req_wstrb, {
	8'h01, 64'hff,	
	8'h03, 64'hffff,
	8'h0f, 64'hffffffff,
	8'hff, 64'hffffffffffffffff
});
wire [63:0] writedata_to_dataram;
MuxKey #(8, 3, 64) i8 (writedata_to_dataram, req_offset, {
	3'b000,  {req_wdata & o_req_wstrb},
	3'b001,  {{{req_wdata & o_req_wstrb}[55:0]},{8'b0}},
	3'b010,  {{{req_wdata & o_req_wstrb}[47:0]},{16'b0}},
	3'b011,  {{{req_wdata & o_req_wstrb}[39:0]},{24'b0}},
	3'b100,  {{{req_wdata & o_req_wstrb}[31:0]},{32'b0}},
	3'b101,  {{{req_wdata & o_req_wstrb}[23:0]},{40'b0}},
	3'b110,  {{{req_wdata & o_req_wstrb}[15:0]},{48'b0}},
	3'b111,  {{{req_wdata & o_req_wstrb}[7:0]}, {56'b0}}
});
wire [127:0] dataram_rdata_i = write_buffer_state & (write_buffer_index[6:1] == req_index[6:1]) & hit_write ? write_buffer_wdata : dataram_rdata;
wire [127:0] write_data = write_buffer_bwen & {{writedata_to_dataram},{writedata_to_dataram}} ;//| ~write_buffer_bwen & {dataram_rdata_i};

always @(posedge clk)begin
  if(rst)begin
    write_buffer_state <= `WRITE_IDLE;
    write_buffer_addr <= 64'b0;
    write_buffer_wstrb <= 8'b0;
    write_buffer_wdata <= 128'b0;
    write_buffer_req <= 1'b0;
  end else begin
    case(write_buffer_state)
      `WRITE_IDLE: begin
        if(~hit_write)begin
	  write_buffer_state <= `WRITE_IDLE;
	end else if (hit_write) begin
	  write_buffer_state <= `WRITE_WRITE;
	  write_buffer_addr <= req_addr;
	  write_buffer_wstrb <= req_wstrb;
	  write_buffer_wdata <= write_data;
	  write_buffer_req   <= req_req;
	  o_write_buffer_bwen <= write_buffer_bwen;
  	end else begin
  	end
      end
      `WRITE_WRITE: begin
         if(~hit_write)begin
	  write_buffer_state <= `WRITE_IDLE;
	  write_buffer_req <= 1'b0;
	end else if (hit_write) begin
	  write_buffer_state <= `WRITE_WRITE;
  	  write_buffer_addr <= req_addr;
	  write_buffer_wstrb <= req_wstrb;
	  write_buffer_wdata <= write_data;
	  write_buffer_req   <= req_req;
	  o_write_buffer_bwen <= write_buffer_bwen;
	end else begin
  	end
      end
    endcase 
  end
end


//cache line size 8 Byte - cache line number 2^9 512 

reg [511:0] dirty_reg;
reg [52:0] tagv_reg [0:511];

wire [8:0] cache_write_index;
wire [52:0] cache_write_tagv;

wire tagv_cen = (cache_state == `IDLE) && i_cache_req || (cache_state == `LOOKUP) ||(cache_state == `REFILL && !uncache) || (cache_state == `MISS) & i_cache_wr_rdy & !uncache;
wire dirty_cen = (write_buffer_state == `WRITE_WRITE) || (cache_state == `REFILL && !uncache) || (cache_state == `MISS) & i_cache_wr_rdy & !uncache;
wire dirty_wen = write_buffer_state == `WRITE_WRITE || (cache_state == `REFILL && !uncache);
wire tagv_wen;
wire dirty;

assign tagv_wen = (i_cache_ret_valid && i_cache_ret_last && !uncache); 
assign cache_write_index = write_buffer_req ? write_buffer_index : req_index;
assign cache_write_tagv = {{req_tag},{1'b1}};
assign dirty =  (write_buffer_state == `WRITE_WRITE) | req_wr ? 1'b1 : 1'b0;

wire [8:0] tagv_r_index = (cache_state == `MISS & i_cache_wr_rdy) ? req_index : index;
always @(posedge clk)begin
  if(dirty_wen && dirty_cen)begin
    dirty_reg[cache_write_index] <= dirty;
  end 
  if(tagv_wen && tagv_cen)begin
    tagv_reg[cache_write_index] <= cache_write_tagv;
  end
    cache_tagv <= tagv_cen  ? tagv_reg[tagv_r_index]  : 53'b0;
    cache_D    <= dirty_cen ? dirty_reg[req_index] : 1'b0;
end

wire [127:0] dataram_rdata1;
wire [127:0] dataram_rdata2;
wire [127:0] dataram_rdata3;
wire [127:0] dataram_rdata4;

wire dataram_cen1;
wire dataram_cen2;
wire dataram_cen3;
wire dataram_cen4;

wire dataram_wen1;
wire dataram_wen2;
wire dataram_wen3;
wire dataram_wen4;

wire [127:0] dataram_bwen1;
wire [127:0] dataram_bwen2;
wire [127:0] dataram_bwen3;
wire [127:0] dataram_bwen4;

wire dataram_wen1_t;
wire dataram_wen2_t;
wire dataram_wen3_t;
wire dataram_wen4_t;

wire [5:0] dataram_addr1;
wire [5:0] dataram_addr2;
wire [5:0] dataram_addr3;
wire [5:0] dataram_addr4;

wire [127:0] dataram_wdata1;
wire [127:0] dataram_wdata2;
wire [127:0] dataram_wdata3;
wire [127:0] dataram_wdata4;

assign dataram_cen1 = !(((index[8:7] == 2'b00) && i_cache_req) || !dataram_wen1 || ((cache_state == `MISS) & i_cache_wr_rdy)); 
assign dataram_cen2 = !(((index[8:7] == 2'b01) && i_cache_req) || !dataram_wen2 || ((cache_state == `MISS) & i_cache_wr_rdy)); 
assign dataram_cen3 = !(((index[8:7] == 2'b10) && i_cache_req) || !dataram_wen3 || ((cache_state == `MISS) & i_cache_wr_rdy)); 
assign dataram_cen4 = !(((index[8:7] == 2'b11) && i_cache_req) || !dataram_wen4 || ((cache_state == `MISS) & i_cache_wr_rdy)); 
/*
assign dataram_wen1 = !(((req_index[8:7] == 2'b00 && (req_wr || (i_cache_ret_valid && i_cache_ret_last) )) || (write_buffer_index[8:7] == 2'b00 && write_buffer_req)) && dataram_wen);
assign dataram_wen2 = !(((req_index[8:7] == 2'b01 && (req_wr || (i_cache_ret_valid && i_cache_ret_last) )) || (write_buffer_index[8:7] == 2'b01 && write_buffer_req)) && dataram_wen);
assign dataram_wen3 = !(((req_index[8:7] == 2'b10 && (req_wr || (i_cache_ret_valid && i_cache_ret_last) )) || (write_buffer_index[8:7] == 2'b10 && write_buffer_req)) && dataram_wen);
assign dataram_wen4 = !(((req_index[8:7] == 2'b11 && (req_wr || (i_cache_ret_valid && i_cache_ret_last) )) || (write_buffer_index[8:7] == 2'b11 && write_buffer_req)) && dataram_wen);
*/

assign dataram_wen1 = !(((req_index[8:7] == 2'b00 && ((i_cache_ret_valid && i_cache_ret_last && !uncache) )) || (write_buffer_index[8:7] == 2'b00 && write_buffer_req)) && dataram_wen);
assign dataram_wen2 = !(((req_index[8:7] == 2'b01 && ((i_cache_ret_valid && i_cache_ret_last && !uncache) )) || (write_buffer_index[8:7] == 2'b01 && write_buffer_req)) && dataram_wen);
assign dataram_wen3 = !(((req_index[8:7] == 2'b10 && ((i_cache_ret_valid && i_cache_ret_last && !uncache) )) || (write_buffer_index[8:7] == 2'b10 && write_buffer_req)) && dataram_wen);
assign dataram_wen4 = !(((req_index[8:7] == 2'b11 && ((i_cache_ret_valid && i_cache_ret_last && !uncache) )) || (write_buffer_index[8:7] == 2'b11 && write_buffer_req)) && dataram_wen);


/*
assign dataram_wen1 = !((req_index[8:7] == 2'b00) && dataram_wen);
assign dataram_wen2 = !((req_index[8:7] == 2'b01) && dataram_wen);
assign dataram_wen3 = !((req_index[8:7] == 2'b10) && dataram_wen);
assign dataram_wen4 = !((req_index[8:7] == 2'b11) && dataram_wen);


wire diff1 = dataram_wen1_t != dataram_wen1 && !dataram_cen1;
wire diff2 = dataram_wen2_t != dataram_wen2 && !dataram_cen2;
wire diff3 = dataram_wen3_t != dataram_wen3 && !dataram_cen3;
wire diff4 = dataram_wen4_t != dataram_wen4 && !dataram_cen4;
*/
assign dataram_bwen1 = write_buffer_req ? ~o_write_buffer_bwen : !req_index[0] ?  128'hffffffffffffffff0000000000000000 : 
				                                                  128'h0000000000000000ffffffffffffffff; 
assign dataram_bwen2 = write_buffer_req ? ~o_write_buffer_bwen : !req_index[0] ?  128'hffffffffffffffff0000000000000000 : 
				                                                  128'h0000000000000000ffffffffffffffff; 
assign dataram_bwen3 = write_buffer_req ? ~o_write_buffer_bwen : !req_index[0] ?  128'hffffffffffffffff0000000000000000 : 
				                                                  128'h0000000000000000ffffffffffffffff; 
assign dataram_bwen4 = write_buffer_req ? ~o_write_buffer_bwen : !req_index[0] ?  128'hffffffffffffffff0000000000000000 : 
				                                                  128'h0000000000000000ffffffffffffffff; 
wire [2:0] dataram_addr1_sel;
assign dataram_addr1_sel[0] = dataram_wen1;
assign dataram_addr1_sel[1] = ~dataram_wen1 & ~write_buffer_req | ((cache_state == `MISS) & i_cache_wr_rdy & req_index[8:7] == 2'b00);
assign dataram_addr1_sel[2] = ~dataram_wen1 & write_buffer_req & write_buffer_index[8:7] == 2'b00;

wire [2:0] dataram_addr2_sel;
assign dataram_addr2_sel[0] = dataram_wen2;
assign dataram_addr2_sel[1] = ~dataram_wen2 & ~write_buffer_req | ((cache_state == `MISS) & i_cache_wr_rdy & req_index[8:7] == 2'b01);
assign dataram_addr2_sel[2] = ~dataram_wen2 & write_buffer_req & write_buffer_index[8:7] == 2'b01;

wire [2:0] dataram_addr3_sel;
assign dataram_addr3_sel[0] = dataram_wen3;
assign dataram_addr3_sel[1] = ~dataram_wen3 & ~write_buffer_req | ((cache_state == `MISS) & i_cache_wr_rdy & req_index[8:7] == 2'b10);
assign dataram_addr3_sel[2] = ~dataram_wen3 & write_buffer_req & write_buffer_index[8:7] == 2'b10;

wire [2:0] dataram_addr4_sel;
assign dataram_addr4_sel[0] = dataram_wen4;
assign dataram_addr4_sel[1] = ~dataram_wen4 & ~write_buffer_req | ((cache_state == `MISS) & i_cache_wr_rdy & req_index[8:7] == 2'b11);
assign dataram_addr4_sel[2] = ~dataram_wen4 & write_buffer_req & write_buffer_index[8:7] == 2'b11;

MuxKey #(4, 3, 6) i14 (dataram_addr1, dataram_addr1_sel, {
	3'b001, index[6:1],	
	3'b010, req_index[6:1],
	3'b011, req_index[6:1],
	3'b100, write_buffer_index[6:1]
});
MuxKey #(4, 3, 6) i16 (dataram_addr2, dataram_addr2_sel, {
	3'b001, index[6:1],	
	3'b010, req_index[6:1],
	3'b011, req_index[6:1],
	3'b100, write_buffer_index[6:1]
});
MuxKey #(4, 3, 6) i17 (dataram_addr3, dataram_addr3_sel, {
	3'b001, index[6:1],	
	3'b010, req_index[6:1],
	3'b011, req_index[6:1],
	3'b100, write_buffer_index[6:1]
});
MuxKey #(4, 3, 6) i18 (dataram_addr4, dataram_addr4_sel, {
	3'b001, index[6:1],	
	3'b010, req_index[6:1],
	3'b011, req_index[6:1],
	3'b100, write_buffer_index[6:1]
});
/*
assign dataram_addr1 = (index[6:1] & {6{dataram_wen1}}) | (req_index[6:1] & {6{~dataram_wen1 & ~write_buffer_req}}) | (write_buffer_index[6:1] & {6{~dataram_wen1 & write_buffer_req}}); 
assign dataram_addr2 = (index[6:1] & {6{dataram_wen2}}) | (req_index[6:1] & {6{~dataram_wen2 & ~write_buffer_req}}) | (write_buffer_index[6:1] & {6{~dataram_wen2 & write_buffer_req}}); 
assign dataram_addr3 = (index[6:1] & {6{dataram_wen3}}) | (req_index[6:1] & {6{~dataram_wen3 & ~write_buffer_req}}) | (write_buffer_index[6:1] & {6{~dataram_wen3 & write_buffer_req}}); 
assign dataram_addr4 = (index[6:1] & {6{dataram_wen4}}) | (req_index[6:1] & {6{~dataram_wen4 & ~write_buffer_req}}) | (write_buffer_index[6:1] & {6{~dataram_wen4 & write_buffer_req}}); 

wire diff1 = dataram_addr1_test != dataram_addr1;
wire diff2 = dataram_addr2_test != dataram_addr2;
wire diff3 = dataram_addr3_test != dataram_addr3;
wire diff4 = dataram_addr4_test != dataram_addr4;
*/
/*
assign dataram_addr1 = dataram_addr;
assign dataram_addr2 = dataram_addr;
assign dataram_addr3 = dataram_addr;
assign dataram_addr4 = dataram_addr;
*/

assign dataram_wdata1 = {axidata_to_dataram} & {128{~write_buffer_req}} 
			| {write_buffer_wdata} & {128{write_buffer_req}};
assign dataram_wdata2 = {axidata_to_dataram} & {128{~write_buffer_req}} 
		 	| {write_buffer_wdata} & {128{write_buffer_req}};
assign dataram_wdata3 = {axidata_to_dataram} & {128{~write_buffer_req}} 
			| {write_buffer_wdata} & {128{write_buffer_req}};
assign dataram_wdata4 = {axidata_to_dataram} & {128{~write_buffer_req}} 
			| {write_buffer_wdata} & {128{write_buffer_req}};

S011HD1P_X32Y2D128_BW dataram1(
	.Q(dataram_rdata1),
	.CLK(clk),
	.CEN(dataram_cen1),
	.WEN(dataram_wen1),
	.BWEN(dataram_bwen1),
	.A(dataram_addr1),
	.D(dataram_wdata1)
);
S011HD1P_X32Y2D128_BW dataram2(
	.Q(dataram_rdata2),
	.CLK(clk),
	.CEN(dataram_cen2),
	.WEN(dataram_wen2),
	.BWEN(dataram_bwen2),
	.A(dataram_addr2),
	.D(dataram_wdata2)
);
S011HD1P_X32Y2D128_BW dataram3(
	.Q(dataram_rdata3),
	.CLK(clk),
	.CEN(dataram_cen3),
	.WEN(dataram_wen3),
	.BWEN(dataram_bwen3),
	.A(dataram_addr3),
	.D(dataram_wdata3)
);
S011HD1P_X32Y2D128_BW dataram4(
	.Q(dataram_rdata4),
	.CLK(clk),
	.CEN(dataram_cen4),
	.WEN(dataram_wen4),
	.BWEN(dataram_bwen4),
	.A(dataram_addr4),
	.D(dataram_wdata4)
);
endmodule
//syn ram
/*
wire [63:0] cache_data;
reg [63:0] instt;

assign cache_data[63:0] = instt[63:0];

always @(posedge clk)begin
	if(rst)begin
	  instt <= 0;
	end
	if(i_cache_req)begin
	  instt <= o_ram_inst;
  	end
end
import "DPI-C" function void mpmem_read(input longint raddr, output longint rdata);
reg [63:0] o_ram_inst;

always @(*) begin
	if(rst)begin
	  o_ram_inst =  0;
	end
	else begin
    	  mpmem_read(i_cache_addr, o_ram_inst);
  end
end
*/
//----------------------------------//


